<template>
  <!-- 表单 -->
  <div :class="{ 'box-e': border }">
    <el-form
      ref="baseForm"
      :model="formData"
      :inline="inline"
      :label-width="labelWidth"
      :size="size"
      :disabled="disabled"
      :label-position="labelPosition"
      border
    >
      <!-- 行内排列 -->
      <template v-if="inline">
        <!-- 表单项 -->
        <template v-for="(formItem, index) in iFormList">
          <el-form-item
            :key="index"
            :label-width="formItem.labelWidth"
            :prop="formItem.key"
            :rules="formItem.rules"
            v-if="true"
            v-show="!formItem.hidden"
          >
            <!-- 标题 -->
            <template v-slot:label>
              {{ formItem.label }}
            </template>
            <!-- 插槽 -->
            <template v-if="formItem.tag === 'slot'">
              <slot :name="formItem.key" :row="formData">
                {{
                  formItem.filter
                    ? formItem.filter(formData)
                    : formData[formItem.key]
                }}
              </slot>
            </template>
            <!-- 单选组件 -->
            <el-radio-group
              v-else-if="formItem.tag === 'el-radio-group'"
              v-model="formData[formItem.key]"
              v-bind="formItem.props"
            >
              <el-radio
                v-for="opt in formItem.options"
                :key="
                  opt[
                    (formItem.optionProps &&
                      formItem.optionProps.id) ||
                      'id'
                  ]
                "
                :label="
                  opt[
                    (formItem.optionProps &&
                      formItem.optionProps.id) ||
                      'id'
                  ]
                "
              >
                {{
                  opt[
                    (formItem.optionProps &&
                      formItem.optionProps.name) ||
                      "name"
                  ]
                }}
              </el-radio>
            </el-radio-group>
            <!-- 其它表单组件 -->
            <component
              v-else
              :is="formItem.tag"
              v-model="formData[formItem.key]"
              v-bind="formItem.props"
            >
              <template
                v-if="formItem.tag === 'el-checkbox-group'"
              >
                <el-checkbox
                  v-for="opt in formItem.options"
                  :key="
                    opt[
                      (formItem.optionProps &&
                        formItem.optionProps.id) ||
                        'id'
                    ]
                  "
                  :label="
                    opt[
                      (formItem.optionProps &&
                        formItem.optionProps.id) ||
                        'id'
                    ]
                  "
                >
                  {{
                    opt[
                      (formItem.optionProps &&
                        formItem.optionProps.name) ||
                        "name"
                    ]
                  }}
                </el-checkbox>
              </template>
              <template v-if="formItem.tag === 'el-select'">
                <el-option
                  v-for="opt in formItem.options"
                  :key="
                    opt[
                      (formItem.optionProps &&
                        formItem.optionProps.id) ||
                        'id'
                    ]
                  "
                  :label="
                    opt[
                      (formItem.optionProps &&
                        formItem.optionProps.name) ||
                        'name'
                    ]
                  "
                  :value="
                    opt[
                      (formItem.optionProps &&
                        formItem.optionProps.id) ||
                        'id'
                    ]
                  "
                >
                </el-option>
              </template>
            </component>
            <!-- 表单项提示框 -->
            <el-popover
              v-if="formItem.tips"
              class="tips-pop"
              placement="top-start"
              title="提示"
              width="320"
              trigger="hover"
              :content="formItem.tips"
            >
              <i
                class="el-icon-question tips-icon"
                slot="reference"
              ></i>
            </el-popover>
          </el-form-item>
          <el-button
            type="success"
            size="mini"
            v-if="formItem.copy"
            @click="copy(formData[formItem.key])"
            >复制</el-button
          >
        </template>
        <div
          style="display: flex; justify-content: flex-end; width: 100%;"
        >
          <slot name="button"></slot>
        </div>
      </template>
      <!-- 栅格排列 -->
      <el-row :gutter="20" v-else>
        <template v-for="(formItem, index) in iFormList">
          <el-col
            :key="index"
            :span="formItem.span"
            v-if="true"
          >
            <el-row :gutter="15">
              <el-col :span="formItem.copy ? 20 : 24">
                <template v-if="formItem.tag === 'title'">
                  <div
                    class="title"
                    v-bind="formItem.props"
                  >
                    <span v-html="formItem.label"></span>
                  </div>
                </template>
                <!-- 表单项 -->
                <el-form-item
                  v-else
                  :label-width="formItem.labelWidth"
                  :prop="formItem.key"
                  :rules="formItem.rules"
                  v-show="!formItem.hidden"
                >
                  <!-- 标题 -->
                  <template v-slot:label>
                    {{ formItem.label }}
                  </template>
                  <!-- 插槽 -->
                  <template v-if="formItem.tag === 'slot'">
                    <slot
                      :name="formItem.key"
                      :row="formData"
                    >
                      {{
                        formItem.filter
                          ? formItem.filter(formData)
                          : formData[formItem.key]
                      }}
                    </slot>
                  </template>
                  <div
                    class="text"
                    v-else-if="formItem.tag === 'text'"
                  >
                    {{ formData[formItem.key] }}
                  </div>
                  <div
                    class="text"
                    v-else-if="
                      formItem.tag === 'selectText'
                    "
                  >
                    {{
                      formItem.options.find(
                        (item) =>
                          item.id === formData[formItem.key]
                      ).name
                    }}
                  </div>
                  <el-cascader
                    v-else-if="
                      formItem.tag === 'el-cascader'
                    "
                    v-model="formData[formItem.key]"
                    :options="formItem.options"
                    v-bind="formItem.props"
                  ></el-cascader>
                  <!-- 数字选择框 -->
                  <el-input-number
                    v-else-if="
                      formItem.tag === 'el-input-number'
                    "
                    v-model="formData[formItem.key]"
                    v-bind="formItem.props"
                  ></el-input-number>
                  <!-- 单选组件 -->
                  <el-radio-group
                    v-else-if="
                      formItem.tag === 'el-radio-group'
                    "
                    v-model="formData[formItem.key]"
                    v-bind="formItem.props"
                  >
                    <el-radio
                      v-for="opt in formItem.options"
                      :key="
                        opt[
                          (formItem.optionProps &&
                            formItem.optionProps.id) ||
                            'id'
                        ]
                      "
                      :label="
                        opt[
                          (formItem.optionProps &&
                            formItem.optionProps.id) ||
                            'id'
                        ]
                      "
                    >
                      {{
                        opt[
                          (formItem.optionProps &&
                            formItem.optionProps.name) ||
                            "name"
                        ]
                      }}
                    </el-radio>
                  </el-radio-group>
                  <!-- 其它表单组件 -->
                  <component
                    v-else
                    style="width: 100%"
                    :is="formItem.tag"
                    v-model="formData[formItem.key]"
                    v-bind="formItem.props"
                  >
                    <template
                      v-if="
                        formItem.tag === 'el-checkbox-group'
                      "
                    >
                      <el-checkbox
                        v-for="opt in formItem.options"
                        :key="
                          opt[
                            (formItem.optionProps &&
                              formItem.optionProps.id) ||
                              'id'
                          ]
                        "
                        :label="
                          opt[
                            (formItem.optionProps &&
                              formItem.optionProps.id) ||
                              'id'
                          ]
                        "
                      >
                        {{
                          opt[
                            (formItem.optionProps &&
                              formItem.optionProps.name) ||
                              "name"
                          ]
                        }}
                      </el-checkbox>
                    </template>
                    <template
                      v-if="formItem.tag === 'el-select'"
                    >
                      <el-option
                        v-for="opt in formItem.options"
                        :key="
                          opt[
                            (formItem.optionProps &&
                              formItem.optionProps.id) ||
                              'id'
                          ]
                        "
                        :label="
                          opt[
                            (formItem.optionProps &&
                              formItem.optionProps.name) ||
                              'name'
                          ]
                        "
                        :value="
                          opt[
                            (formItem.optionProps &&
                              formItem.optionProps.id) ||
                              'id'
                          ]
                        "
                      >
                      </el-option>
                    </template>
                  </component>
                  <!-- 表单项提示框 -->
                  <el-popover
                    v-if="formItem.tips"
                    class="tips-pop"
                    placement="top-start"
                    title="提示"
                    width="320"
                    trigger="hover"
                    :content="formItem.tips"
                  >
                    <i
                      class="el-icon-question tips-icon"
                      slot="reference"
                    ></i>
                  </el-popover>
                </el-form-item>
              </el-col>
              <el-col :span="2" v-if="formItem.copy">
                <el-button
                  type="primary"
                  plain
                  :size="size"
                  @click="copy(formData[formItem.key])"
                  >复制</el-button
                >
              </el-col>
            </el-row>
          </el-col>
        </template>
      </el-row>
    </el-form>
  </div>
</template>

<script setup>
import {
  onMounted,
  reactive,
  watch,
  defineProps,
  ref,
  defineExpose
} from "vue";
import useClipboard from "vue-clipboard3";

// 复制
const { toClipboard } = useClipboard();

const props = defineProps({
  // 表单配置
  formList: {
    type: Array,
    default: () => []
  },
  // 表单数据
  formData: {
    type: Object,
    default: () => ({})
  },
  // 行内展示
  inline: {
    type: Boolean,
    default: false
  },
  // 标题宽度
  labelWidth: {
    type: String,
    default: ""
  },
  // 表单大小
  size: {
    type: String,
    default: "large"
  },
  // 禁用
  disabled: {
    type: Boolean,
    default: false
  },
  // 标签的位置
  labelPosition: {
    type: String,
    default: "top"
  },
  border: {
    type: Boolean,
    default: true
  }
});

// 表单数据
const iFormData = reactive({});
// 表单配置
const iFormList = ref([]);
// 表单对象节点
const baseForm = ref(null);
// 接口获取所有选项数据
const options = reactive({});

// 复制
async function copy(e) {
  await toClipboard(e);
  ElMessage.success("复制成功");
}

// 监听
watch(
  () => props.formList,
  () => {
    initFormList();
  },
  { deep: true }
);

// 监听
watch(
  () => props.formData,
  (val, oldVal) => {
    initFormList();
  },
  { deep: true }
);

// 监听
watch(
  options,
  () => {
    initFormList();
  },
  { deep: true }
);

onMounted(() => {
  initFormList();
});

// 初始化iFormList
function initFormList() {
  const { formList, formData } = props;
  iFormList.value = formList.map((item, _index) => {
    const newItem = deepClone(item);
    if (item.key && !(item.key in formData)) {
      if ("default" in item) {
        formData[item.key] = item.default;
        // formData.$set(formData, item.key, item.default);
      } else if (!["slot", "title"].includes(item.tag)) {
        formData[item.key] = "";
        // formData.$set(formData, item.key, "");
      }
    }
    newItem.vshow = true;
    if (item.vshow === false) {
      newItem.vshow = false;
    }
    if (
      item.options &&
      typeof item.options === "function"
    ) {
      delete newItem.options;
      if (options[item.key]) {
        // newItem.options = [...options[item.key]];
      }
    }

    return {
      ...newItem
    };
  });
}

// 深拷贝函数
function deepClone(obj) {
  if (typeof obj === "string") {
    return obj;
  }
  if (typeof obj === "number") {
    return obj;
  }
  if (typeof obj === "boolean") {
    return obj;
  }
  if (typeof obj === "undefined") {
    return obj;
  }
  if (typeof obj === "function") {
    return obj;
  }
  if (obj === null) {
    return obj;
  }
  if (Array.isArray(obj)) {
    const newObj = [];
    obj.forEach((item) => {
      newObj.push(deepClone(item));
    });
    return newObj;
  }
  const newObj = {};
  for (let key in obj) {
    newObj[key] = deepClone(obj[key]);
  }
  return newObj;
}

// 清空表单
const resetForm = () => {
  baseForm.value.resetFields();
};

// 验证表单
const checkValidate = () => {
  return new Promise((resolve, reject) => {
    baseForm.value.validate((bool) => {
      if (bool) {
        resolve();
      } else {
        reject();
      }
    });
  });
};

// 暴露方法
defineExpose({
  resetForm,
  checkValidate
});
</script>

<style lang="scss" scoped>
.title {
  font-size: 18px;
  font-weight: bold;
  margin-bottom: 20px;
}
.text {
}
</style>
